--[[
Uber credits must be given to nymbia for the metatables and frames, thanks!
]]
--Ace2 Registering
ClassTimer = AceLibrary('AceAddon-2.0'):new('AceConsole-2.0', 'AceEvent-2.0', 'AceDB-2.0', 'FuBarPlugin-2.0')

local ClassTimer, self = ClassTimer, ClassTimer

local dewdrop = AceLibrary('Dewdrop-2.0')
local L = AceLibrary('AceLocale-2.2'):new('ClassTimer')
local sm = LibStub("LibSharedMedia-3.0")

local _G = _G
local unpack = _G.unpack
local GetTime = _G.GetTime
local table_sort = _G.table.sort
local math_ceil = _G.math.ceil
local gsub = _G.gsub
local pairs = _G.pairs
local ipairs = _G.ipairs
local UnitIsUnit = _G.UnitIsUnit

local _, enClass = UnitClass("player")
local hasPet = enClass=="HUNTER" or enClass=="WARLOCK" and true
local sticky = {}
local unlocked = {}

local new, del
do
	local cache = setmetatable({}, {__mode='k'})
	function new()
		local t = next(cache)
		if t then
			cache[t] = nil
			return t
		else
			return {}
		end
	end
	function del(t)
		for k in pairs(t) do
			t[k] = nil
		end
		cache[t] = true
		return nil
	end
end
local OnUpdate
local bars
do
	local min = L['%dm']
	local seclong = L['%ds']
	local secshort = L['%.1fs']
	local function timenum(num)
		if num <= 10 then
			return secshort:format(num)
		elseif num <= 60 then
			return seclong:format(num)
		else
			return min:format(math_ceil(num / 60))
		end
	end
	function OnUpdate(frame)
		local currentTime = GetTime()
		local endTime = frame.endTime
		local startTime = frame.startTime
		if currentTime > endTime then
			if unlocked[frame.unit] then unlocked[frame.unit] = nil unlocked.General = nil end
			if frame.unit ~= "sticky" then
				self:UpdateUnitBars(frame.unit)
			else
				bars.sticky[sticky[frame.name..frame.unitname]]:Hide()
				self:StickyUpdate(sticky[frame.name..frame.unitname])
			end
		else
			local elapsed = (currentTime - startTime)
			frame.timetext:SetText(timenum(endTime - currentTime))
			local sp = frame:GetWidth()*elapsed/(endTime-startTime)
			if frame.reversed then
				frame:SetValue(startTime + elapsed)
				-- | frame.spark:SetPoint('CENTER', frame, 'LEFT', sp, 0)
			else
				frame:SetValue(endTime - elapsed)
				-- | frame.spark:SetPoint('CENTER', frame, 'RIGHT', -sp, 0)
			end
		end
		
	end
end
do 
	local function MouseUp(bar, button)
		if unlocked[bar.unit] and IsModifierKeyDown() then
			dewdrop:Open(bar, 'children', function() dewdrop:FeedAceOptionsTable(self.Menu.args.BarSettings.args[bar.unit]) end)
			return
		end
		
		if self.db.profile.Units[bar.unit].click then
			if button == 'RightButton' then 
				local msg = L['%s has %s left']:format(bar.text:GetText(), bar.timetext:GetText()) 
				if UnitInRaid('player') then
					SendChatMessage(msg, 'RAID')
				elseif GetNumPartyMembers() > 0 then
					SendChatMessage(msg, 'PARTY')
				end
			end
		end
	end

	local framefactory = {
		__index = function(t,k)
			local bar = CreateFrame('StatusBar', nil, UIParent)
			t[k] = bar
			bar:SetFrameStrata('MEDIUM')
			bar:Hide()
			bar:SetClampedToScreen(true)
			bar:SetScript('OnUpdate', OnUpdate)
			bar:SetBackdrop({bgFile = 'Interface\\Tooltips\\UI-Tooltip-Background', tile = true, tileSize = 16})
			bar.text = bar:CreateFontString(nil, 'OVERLAY')
			bar.timetext = bar:CreateFontString(nil, 'OVERLAY')
			bar.icon = bar:CreateTexture(nil, 'DIALOG')
			bar:SetScript('OnMouseUp', MouseUp)
			
			--[[local spark = bar:CreateTexture(nil, "OVERLAY")
			bar.spark = spark
			spark:SetTexture("Interface\\CastingBar\\UI-CastingBar-Spark")
			spark:SetWidth(16)
			spark:SetBlendMode("ADD")
			spark:Show()]]
			self:ApplySettings()
			return bar
		end
	}

	bars = {
		target = setmetatable({}, framefactory),
		focus  = setmetatable({}, framefactory),
		player = setmetatable({}, framefactory),
		sticky = setmetatable({}, framefactory),
		pet    = hasPet and setmetatable({}, framefactory) or nil
	}
	ClassTimer.bars = bars
end

ClassTimer:RegisterDB('ClassTimerDB')

ClassTimer.defaults = {
	Abilities = {},
	Custom    = {},
	Group     = {},
	Sticky    = { ['*'] = false },
	Units     = { 
		['**']     = {
			enable          = true,
			buffs           = true,
			click           = false,
			debuffs         = true,
			differentColors = false,
			growup          = false,
			showIcons       = false,
			icons           = true,
			iconSide        = 'LEFT',
			scale           = 1,
			spacing         = 0,
			nametext        = true,
			timetext        = true,
			texture         = 'Blizzard',
			width           = 150,
			height          = 16,
			font            = 'Friz Quadrata TT',
			fontsize        = 9,
			alpha           = 1,
			scale           = 1,
			bartext         = '%s (%a) (%u)',
			sizeEnable      = false,
			sizeMax         = 5,
			buffcolor       = {0,0.49, 1, 1},
			Poisoncolor     = {0, 1, 0, 1},
			Magiccolor      = {0, 0, 1, 1},
			Diseasecolor    = {.55, .15, 0, 1},
			Cursecolor      = {5, 0, 5, 1},
			debuffcolor     = {1.0,0.7, 0, 1},
			backgroundcolor = {0,0, 0, 1},
			textcolor       = {1,1,1},
		},
		['sticky'] = { enable = false },
		['focus']  = { click = true }
	},
}

 
function ClassTimer:OnInitialize()
--Revision 
	local revision = tonumber(string.match('$Rev: 68992 $', '%d+'))
	self.version = self.revision and self.version .. ' |cffff8888r'..revision..'|r'

	local validate = {}
	local timerargs = {}
	local table =  self:CreateTimers()
	table['Race'] = self:Races()
	for k, v in pairs(table) do
		for n in ipairs(v) do
			ClassTimer.defaults.Abilities[v[n]] = true
		end
		local k = L[k]
		timerargs[k] = {
			type = 'text',
			order = 4,
			name = k,
			desc = L['Which Buffs to show.'],
			onClick = function() local value = not self.db.profile.Abilities[v[1]] for _, n in ipairs(v) do self.db.profile.Abilities[n] = value end end,
			get = function(key) return self.db.profile.Abilities[key] end,
			set = function(key, value) self.db.profile.Abilities[key] = value validate[key] = value and key or nil end,
			validate = v,
			multiToggle = true,
		}
	end
	self:RegisterDefaults('profile', self.defaults)
	timerargs.Extras = {
		type = 'group',
		name = L['Extras'],
		desc = L['Other abilities'],
		order = 99,
		args = {
			Add = {
				type = 'text',
				name = L['Add'],
				desc = L['Add a custom timer'],
				get = false,
				set = function(value) self.db.profile.Custom[value] = value self.db.profile.Abilities[value] = true validate[value] = value end,
				usage = L['<Spell Name in games locale>']
			},
			Remove = {
				type = 'text',
				name = L['Remove'],
				desc = L['Remove a custom timer'],
				multiToggle = true,
				get = function() return false end,
				set = function(key) self.db.profile.Custom[key] = nil self.db.profile.Abilities[key] = nil validate[key] = nil end,
				validate = self.db.profile.Custom,
			}
		}
	}
	self.Menu.args.Timers = { type = 'group', order = 1, name = L['Timers'], desc = L['Enable or disable timers'], args = timerargs, disabled = '~IsActive' }
	for v in pairs(ClassTimer.defaults.Abilities) do
		if self.db.profile.Abilities[v] then
			validate[v] = v
		end
	end
	for v in pairs(self.db.profile.Custom) do
		validate[v] = v
	end
	if not ClassTimerDB.version or ClassTimerDB.version < 43008 then
		for v in pairs(self.db.profile.Abilities) do 
			self.db.profile.Abilities[v] = self.defaults.Abilities[v] and true
		end
	end
	ClassTimerDB.version = revision
	self.Menu.args.BarSettings.args.sticky.args.addSticky = {
		type = 'text',
		name = L['Add Sticky'],
		desc = L['Add a move to be sticky'],
		get =  function(v) return self.db.profile.Sticky[v] end,
		order = 5,
		set = function(v, u) self.db.profile.Sticky[v] = u end,
		multiToggle = true,
		hidden = function() return not self.db.profile.Units.sticky.enable end,
		validate = validate
	}
	self:RegisterChatCommand('/ClassTimer', self.Menu)
end

function ClassTimer:OnEnable()
	self:RegisterBucketEvent('UNIT_AURA', 0.25)
	self:RegisterEvent('PLAYER_TARGET_CHANGED')
	self:RegisterEvent('PLAYER_FOCUS_CHANGED')
	self:RegisterEvent('PLAYER_PET_CHANGED')
	sm.RegisterCallback(self, "LibSharedMedia_SetGlobal", function(mediatype, override)
		if mediatype == 'statusbar' then
			for _, k in pairs(bars) do
				for _, v in pairs(k) do
					v:SetStatusBarTexture(sm:Fetch('statusbar', override))
				end
			end
		end
	end)
end

function ClassTimer:OnDisable()
	for _, k in pairs(bars) do
		for _, v in pairs(k) do
			v:Hide()
		end
	end
end

function ClassTimer:PLAYER_TARGET_CHANGED()
	self:UpdateUnitBars('target')
end

function ClassTimer:PLAYER_FOCUS_CHANGED()
	self:UpdateUnitBars('focus')
end

function ClassTimer:PLAYER_PET_CHANGED()
	self:UpdateUnitBars('pet')
end

function ClassTimer:UNIT_AURA(units)
	for unit in pairs(units) do
		self:UpdateUnitBars(unit)
	end
end

do
	local function sortup(a,b)
			return a.remaining > b.remaining
	end
	local function sort(a,b)
			return a.remaining < b.remaining
	end
	local function text(text, spell, apps, unit)
		local str = text
		str = gsub(str, '%%s', spell)
		str = gsub(str, '%%u', L[unit])
		str = gsub(str, '%%n', GetUnitName(unit))
		if apps and apps > 1 then
			str = gsub(str, '%%a', apps)
		else
			str = gsub(str, '%%a', '')
		end
		str = gsub(str, '%s%s+', ' ') 
		str = gsub(str, '%p%p+', '')
		str = gsub(str, '%s+$', '')		
		return str
	end
	local tmp = {}
	local called = false -- prevent recursive calls when new bars are created.
	local stickyset = false
	function ClassTimer:GetBuffs(unit, db)
		local currentTime = GetTime()
		if db.buffs then
			for i = 1, 32 do
				local name, _, texture, count, duration, remaining = UnitBuff(unit, i)
				if not name then
					break
				end
				if duration and duration > 0 and self.db.profile.Abilities[name] then
					local t = new()
					if self.db.profile.Units.sticky.enable and self.db.profile.Sticky[name] then
						t.startTime = (currentTime - duration + remaining)
						t.endTime = (currentTime + remaining)
						stickyset = true
						t.unitname = UnitName(unit)
						number = sticky[name..t.unitname] or #sticky+1
						sticky[number] = t
						sticky[name..t.unitname] = number
					else
						tmp[#tmp+1] = t
					end
					t.name = name
					t.unit = unit
					t.texture = texture
					t.duration = duration
					t.remaining = remaining
					t.count = count
					t.isbuff = true
				end
			end
		end
		if db.debuffs then
			for i = 1, 40 do
				local name, _, texture, count, dispelType, duration, remaining = UnitDebuff(unit, i)
				if not name then
					break
				end
				if duration and duration > 0 and self.db.profile.Abilities[name] then
					local t = new()
					if self.db.profile.Units.sticky.enable and self.db.profile.Sticky[name] then
						t.startTime = (currentTime - duration + remaining)
						t.endTime = (currentTime + remaining)
						stickyset = true
						t.unitname = UnitName(unit)
						number = sticky[name..t.unitname] or #sticky+1
						sticky[number] = t
						sticky[name..t.unitname] = number
					else
						tmp[#tmp+1] = t
					end
					t.name = name
					t.unit = unit
					t.texture = texture
					t.duration = duration
					t.remaining = remaining
					t.count = count
					t.dispelType = dispelType
				end
			end
		end
	end
	function ClassTimer:UpdateUnitBars(unit)
		if not bars[unit] then return end
		local db = self.db.profile.Units[unit]
		if unlocked[unit] then return end
		if self.db.profile.Group[unit] then unit = self.db.profile.AllInOneOwner end
		if called then
			return
		end
		called = true
		if db.enable then
			local currentTime = GetTime()
			for k in pairs(tmp) do
				tmp[k] = del(tmp[k])
			end
			self:GetBuffs(unit, db)
			if self.db.profile.Group[unit] then
				for k, v in pairs(self.db.profile.Group) do
					if v then
						if k ~= 'focus' then
							if not UnitIsUnit(k, unit) then self:GetBuffs(k, db) end
						else
							if not UnitIsUnit(k, unit) and not UnitIsUnit(k, 'target') then self:GetBuffs(k, db) end
						end
					end
				end
			end
			table_sort(tmp, db.growup and sortup or sort)
			for k,v in ipairs(tmp) do
				local bar = bars[unit][k]
				
				bar.text:SetText(text(db.bartext, v.name, v.count, v.unit))
				bar.icon:SetTexture(v.texture)
				local elapsed = (v.duration - v.remaining)
				local startTime, endTime = (currentTime - elapsed), (currentTime + v.remaining)
				bar.startTime = startTime
				bar.unit = unit
				bar.duration = v.duration
				bar.endTime = endTime
				bar.isbuff = v.isbuff
				if db.reversed then
					bar.reversed = true
				else
					bar.reversed = nil
				end
				if db.sizeEnable then
					if bar.duration < db.sizeMax then
						local width = (bar.duration/db.sizeMax)*db.width
						bar:SetWidth(width)
						bar.timetext:SetWidth(width)
						bar.text:SetWidth(width - db.fontsize * 2.5)
					else
						bar:SetWidth(db.width)
						bar.timetext:SetWidth(db.width)
						bar.text:SetWidth(db.width - db.fontsize * 2.5)
					end
				end
				if not db.showIcons then
					if bar.isbuff then
						bar:SetStatusBarColor(unpack(db.buffcolor))
					elseif db.differentColors and v.dispelType then
						bar.dispelType = v.dispelType
						bar:SetStatusBarColor(unpack(db[v.dispelType .. 'color']))
					else
						bar:SetStatusBarColor(unpack(db.debuffcolor))
					end
				end
				bar:SetMinMaxValues(startTime, endTime)
				bar:Show()
			end
			for i = #tmp+1, #bars[unit] do
				bars[unit][i]:Hide()
			end
		else
			for _, v in ipairs(bars[unit]) do
				v:Hide()
			end
		end
		if stickyset then
			self:StickyUpdate()
			stickyset = nil
		end
		called = false
	end
	function ClassTimer:StickyUpdate(del)
		local db = self.db.profile.Units.sticky
		if unlocked.sticky then return end
		if db.enable then
			if del then
				for k = del, #sticky do
					local frame = bars.sticky[k+1]
					sticky[del] = nil
					if not sticky[k] and sticky[k+1] then
						sticky[k] = sticky[k+1]
						--sticky[frame.name..frame.unitname] = k
						if sticky[k+1] == #sticky then
							sticky[k+1] = nil
						end
					end
				end
			end
			for k,v in ipairs(sticky) do
				local bar = bars.sticky[k]
				bar.text:SetText(text(db.bartext, v.name, v.count, v.unit))
				bar.icon:SetTexture(v.texture)
				bar.startTime = v.startTime
				bar.unit = 'sticky'
				bar.unitname = v.unitname
				bar.duration = v.duration
				bar.sticky = v.sticky
				bar.endTime = v.endTime
				bar.isbuff = v.isbuff
				bar.name = v.name
				if db.sizeEnable then
					if bar.duration < db.sizeMax then
						local width = (bar.duration/db.sizeMax)*db.width
						bar:SetWidth(width)
						bar.timetext:SetWidth(width)
						bar.text:SetWidth(width - db.fontsize * 2.5)
					else
						bar:SetWidth(db.width)
						bar.timetext:SetWidth(db.width)
						bar.text:SetWidth(db.width - db.fontsize * 2.5)
					end
				end
				if db.reversed then
					bar.reversed = true
				else
					bar.reversed = nil
				end
				if not db.showIcons then
					if bar.isbuff then
						bar:SetStatusBarColor(unpack(db.buffcolor))
					elseif db.differentColors and v.dispelType then
						bar.dispelType = v.dispelType
						bar:SetStatusBarColor(unpack(db[v.dispelType .. 'color']))
					else
						bar:SetStatusBarColor(unpack(db.debuffcolor))
					end
				end
				bar:SetMinMaxValues(v.startTime, v.endTime)
				bar:Show()
			end
			for i = #sticky+1, #bars.sticky do
				bars.sticky[i]:Hide()
			end
		else
			for _, v in ipairs(bars.sticky) do
				v:Hide()
			end
		end
	end
end
do
	local function apply(unit, i, bar, db)
		local bars = bars[unit]
		local showIcons = db.showIcons 
		local spacing = db.spacing
		
		bar:ClearAllPoints()
		bar:SetStatusBarTexture(sm:Fetch('statusbar', db.texture))
		bar:SetHeight(db.height)
		bar:SetScale(db.scale)
		bar:SetAlpha(db.alpha)
		bar:SetWidth(db.width)
		if db.sizeEnable and bar.duration and bar.duration < db.sizeMax then
			local width = (bar.duration/db.sizeMax)*db.width
			bar:SetWidth(width)
			bar.timetext:SetWidth(width)
			bar.text:SetWidth(width - db.fontsize * 2.5)
		else
			bar:SetWidth(db.width)
			bar.timetext:SetWidth(db.width)
			bar.text:SetWidth(db.width - db.fontsize * 2.5)
		end
		-- | bar.spark:SetHeight(db.height + 25)
		if showIcons then
			bar:SetStatusBarColor(1, 1, 1, 0)
			bar:SetBackdropColor(1, 1, 1, 0)
			-- | bar.spark:Hide()
			bar.text:SetFont(sm:Fetch('font', db.font), db.fontsize)
		else 
			if not db.showIcons then
				if bar.isbuff then
					bar:SetStatusBarColor(unpack(db.buffcolor))
				elseif db.differentColors and bar.dispelType then
					bar:SetStatusBarColor(unpack(db[bar.dispelType..'color']))
				else
					bar:SetStatusBarColor(unpack(db.debuffcolor))
				end
			end
			-- | bar.spark:Show()
			bar:SetBackdropColor(unpack(db.backgroundcolor))
		end
		if db.click or unlocked[unit] then
			bar:EnableMouse(true)
		else
			bar:EnableMouse(false)
		end
		if db.reversed then
			bar.reversed = true
		else
			bar.reversed = nil
		end
		if i == 1 then
			if db.x then
				bar:SetPoint('BOTTOMLEFT', UIParent, 'BOTTOMLEFT', db.x, db.y)
			else
				bar:SetPoint('CENTER', UIParent)
			end
		else 
			if db.growup then
				bar:SetPoint('BOTTOMLEFT', bars[i-1], 'TOPLEFT', 0, spacing)
			else 
				bar:SetPoint('TOPLEFT', bars[i-1], 'BOTTOMLEFT', 0, -1 * spacing)
			end
		end
		
		local timetext = bar.timetext
		if db.timetext then
			timetext:Show()
			timetext:ClearAllPoints()
			timetext:SetFont(sm:Fetch('font', db.font), db.fontsize)
			timetext:SetShadowColor( 0, 0, 0, 1)
			timetext:SetShadowOffset( 0.8, -0.8 )
			timetext:SetTextColor(unpack(db.textcolor))
			timetext:SetNonSpaceWrap(false)
			timetext:ClearAllPoints()
			timetext:SetPoint('LEFT', bar, 'LEFT', showIcons and 2 or -2, 0)
			timetext:SetJustifyH(showIcons and 'LEFT' or 'RIGHT')
		else
			timetext:Hide()
		end
		
		local text = bar.text
		text:SetFont(sm:Fetch('font', db.font), db.fontsize)
		if db.nametext and not showIcons then
			text:Show()
			text:ClearAllPoints()
			text:SetShadowColor( 0, 0, 0, 1)
			text:SetShadowOffset( 0.8, -0.8 )
			text:SetTextColor(unpack(db.textcolor))
			text:SetNonSpaceWrap(false)
			text:ClearAllPoints()
			text:SetHeight(db.height)
			text:SetPoint('LEFT', bar, 'LEFT', 2, 0)
			text:SetJustifyH('LEFT')
		else
			text:Hide()
		end

		local icon = bar.icon
		if db.icons then
			icon:Show()
			icon:SetWidth(db.height)
			icon:SetHeight(db.height)
			icon:SetTexCoord(0.07, 0.93, 0.07, 0.93)
			icon:ClearAllPoints()
			if db.iconSide == 'LEFT' then
				icon:SetPoint('RIGHT', bar, 'LEFT', 0, 0)
			else
				icon:SetPoint('LEFT', bar, 'RIGHT', 0, 0)
			end
		else
			icon:Hide()
		end
	end
	function ClassTimer:ApplySettings()
		for n, k in pairs(bars) do
			for u, v in pairs(k) do
				apply(n, u, v, ClassTimer.db.profile.Units[n])
			end
		end
	end
end 

do
	local function dragstart()
		this:StartMoving()
	end
	local function dragstop()
		ClassTimer.db.profile.Units[this.unit].x = this:GetLeft()
		ClassTimer.db.profile.Units[this.unit].y = this:GetBottom()
		this:StopMovingOrSizing()
	end
	local function set(table, value)
		local s1, s2 = unpack(table)
		if s1 == "General" then
			for k in pairs(bars) do
				if s2 then
					ClassTimer.db.profile.Units[k][s2] = value
				else
					ClassTimer.db.profile[k] = value
				end
			end
		end
		if s2 then
			ClassTimer.db.profile.Units[s1][s2] = value
		else
			ClassTimer.db.profile[s1] = value
		end
			ClassTimer.ApplySettings()
	end
	local function get(table)
		local s1, s2 = unpack(table)
		if s2 then
			return ClassTimer.db.profile.Units[s1][s2]
		else
			return ClassTimer.db.profile[s1]
		end
	end
	local function setcolor(field, ...)
		ClassTimer.db.profile.Units[field[1]][field[2]] = {...}
		ClassTimer.ApplySettings()
	end
	local function getcolor(field)
		return unpack(ClassTimer.db.profile.Units[field[1]][field[2]])
	end 
	local function hideoptions(unit)	
		return not ClassTimer.db.profile.Units[unit[1]].enable
	end
	local function Unit(unit)
		return {
			type = 'group',
			name = L[unit],
			desc = L[unit] .. (unit == 'sticky' and ' - ' .. L['BUGGY AND NOT FULLY SUPORTED!!!'] or ''),
			order = unit == 'General' and 20 or 1,
			onClick = function() self.db.profile.Units[unit].enable = not self.db.profile.Units[unit].enable end,
			passValue = {unit, 'enable'},
			disabled = function() return self.db.profile.Group[unit] and unit ~= self.db.profile.AllInOneOwner end,
			args = {
				show = {
					type = 'toggle',
					name = L['Enable %s']:format(L[unit]),
					desc = L['Show buffs/debuffs for your %s']:format(L[unit]),
					get = get,
					set = set,
					passValue = {unit, 'enable'},
					order = 1,
				},
				space = {
					type = 'header',
					order = 2,
					passValue = {unit},
					hidden = function() return not self.db.profile.Units[unit].enable end,
				},
				buffs = {
					type = 'toggle',
					name = L['Enable Buffs'],
					desc = L['Show buffs for your %s']:format(L[unit]),
					get = get,
					set = set,
					order = 3,
					passValue = {unit, 'buffs'},
					hidden = function() return not self.db.profile.Units[unit].enable end,
				},
				debuffs = {
					type = 'toggle',
					name = L['Enable Debuffs'],
					desc = L['Show debuffs for your %s']:format(L[unit]),
					get = get,
					order = 4,
					set = set,
					passValue = {unit, 'debuffs'},
					hidden = function() return not self.db.profile.Units[unit].enable end,
				},
				sizes = {
					type = 'group',
					name = L['Change size'],
					desc = L['Change bar size depending on duration if its less that the max time setting for your %s']:format(L[unit]),
					order = 5,
					passValue = {unit},
					hidden = function() return not self.db.profile.Units[unit].enable end,
					args = {
						enable = {
							type = 'toggle',
							name = L['Enable'],
							desc = L['Enable changing of bar size depending on duration if its less that the max time setting'],
							get = get,
							set = set,
							order = 1,
							passValue = {unit, 'sizeEnable'}
						},
						maxTime = {
							type = 'range',
							name = L['Max time'],
							desc = L['Max time to change bar sizes for'],
							get = get,
							order = 2,
							set = set,
							max = 60,
							min = 5,
							step = .5,
							bigStep = 1,
							passValue = {unit, 'sizeMax'},
							hidden = function() return not self.db.profile.Units[unit].sizeEnable end,
						}
					}
				},
				lock = {
					type = 'toggle',
					name = L['Lock'],
					desc = L['Toggle Cast Bar lock'],
					order = 5,
					hidden = function() return not self.db.profile.Units[unit].enable end,
					passValue = {unit},
					get = function()
						return not unlocked[unit]
					end,
					set = function(unita, v)
						local unit = unita[1]
						if not unit then
							return
						end
						if unit == 'General' then
							for k in pairs(bars) do
								self.Menu.args.BarSettings.args[unit].args.lock.set({k}, v)
							end
							unlocked.General = not v
							return
						end
						unlocked[unit] =  not v
						if v or not self.db.profile.Units[unit].enable or (self.db.profile.Group[unit] and unit ~= self.db.profile.AllInOneOwner) then
							bars[unit][1]:SetScript('OnDragStart', nil)
							bars[unit][1]:SetScript('OnDragStop', nil)
							if not self.db.profile.Units[unit].click then
								bars[unit][1]:EnableMouse(false)
							end
						else
							local bar = bars[unit][1]
							if unit == 'sticky' then
								sticky[1] = {}
								sticky["Test"] = {}
								sticky.name = "Test"
								sticky["Test"][1] = GetTime() + 120
								bar.sticky = 1
							end
							bar.icon:SetTexture("Interface\\Icons\\Ability_Druid_Enrage")
							bar.text:SetText(L['%s, Drag to move']:format(L[unit]))
							bar:EnableMouse(true)
							bar:SetMovable(true)
							bar.startTime = GetTime()
							bar.endTime = GetTime() + 120
							bar:SetMinMaxValues(GetTime(),  GetTime() + 120)
							bar:RegisterForDrag('LeftButton')
							bar.unit = unit
							bar:SetScript('OnDragStart', dragstart)
							bar:SetScript('OnDragStop', dragstop)
							bar:SetAlpha(1)
							bar:Show()
						end
						if unit == 'sticky' then
							if v and sticky[1] then sticky[1] = del(sticky[1]) end
							ClassTimer:StickyUpdate()
						else
							ClassTimer:UpdateUnitBars(unit)
						end
					end,
				},
				alpha = {
					type = 'range',
					name = L['Alpha'],
					desc = L['Set the alpha of the bars'],
					min = 0.05,
					max = 1,
					step = 0.01,
					bigStep = .1,
					isPercent = true,
					get = get,
					set = set,
					hidden = function() return not self.db.profile.Units[unit].enable end,
					passValue = {unit, 'alpha'},
					order = 10,
				},
				fontsize = {
					type = 'range',
					name = L['Font Size'],
					desc = L['Set the font size for the bars'],
					min = 3,
					max = 15,
					step = .5,
					bigStep = 2,
					get = get,
					set = set,
					hidden = function() return not self.db.profile.Units[unit].enable end,
					passValue = {unit, 'fontsize'},
					order = 11,
				},
				height = {
					type = 'range',
					name = L['Bar Height'],
					desc = L['Set the height of the bars'],
					min = 4,
					max = 25,
					step = 2,
					bigStep = 5,
					get = get,
					set = set,
					hidden = function() return not self.db.profile.Units[unit].enable end,
					passValue = {unit, 'height'},
					order = 12,
				},
				scale = {
					type = 'range',
					name = L['Scale'],
					desc = L['Set the scale of the bars for your %s']:format(L[unit]),
					get = get,
					set = set,
					min = .1,
					max = 2,
					step = .01,
					bigStep = .1,
					order = 13,
					passValue = {unit, 'scale'},
					hidden = function() return not self.db.profile.Units[unit].enable end,
				},
				spacing = {
					type = 'range',
					name = L['Spacing'],
					desc = L['Tweak the space between bars for your %s']:format(L[unit]),
					min = -5,
					max = 5,
					step = .1,
					bigStep = 1,
					get = get,
					set = set,
					passValue = {unit, 'spacing'},
					order = 14,
					hidden = function() return not self.db.profile.Units[unit].enable end,
				},
				width = {
					type = 'range',
					name = L['Bar Width'],
					desc = L['Set the width of the bars'],
					min = 50,
					max = 300,
					step = 2,
					bigStep = 5,
					get = get,
					set = set,
					hidden = function() return not self.db.profile.Units[unit].enable end,
					passValue = {unit, 'width'},
					order = 15,
				},
				font = {
					type = 'text',
					name = L['Font'],
					desc = L['Set the font used in the bars'],
					validate = sm:List('font'),
					get = get,
					set = set,
					hidden = function() return not self.db.profile.Units[unit].enable end,
					passValue = {unit, 'font'},
					order = 20,
				},
				iconside = {
					type = 'text',
					name = L['Icon Position'],
					desc = L['Set the side of the bar that the icon appears on'],
					get = get,
					set = set,
					validate = {LEFT = L['Left'], RIGHT = L['Right']},
					passValue = {unit, 'iconSide'},
					order = 21,
					hidden = function() return not self.db.profile.Units[unit].enable end,
				},
				texture = {
					type = 'text',
					name = L['Texture'],
					desc = L['Set the bar Texture'],
					validate = sm:List('statusbar'),
					order = 22,
					get = get,
					set = set,
					hidden = function() return not self.db.profile.Units[unit].enable end,
					passValue = {unit, 'texture'},
				},
				text = {
					type = 'text',
					name = L['Bar Text'],
					desc = L['Set the bar text'],
					get = get,
					set = set,
					order = 23,
					usage = L['<%s for spell, %a for applications, %n for name, %u for unit>'],
					hidden = function() return not self.db.profile.Units[unit].enable end,
					passValue = {unit, 'bartext'},
				},
				textcolor = {
					type = 'color',
					name = L['Text Color'],
					desc = L['Set the color of the text for the bars'],
					get = getcolor,
					set = setcolor,
					passValue = {unit, 'textcolor'},
					hidden = function() return not self.db.profile.Units[unit].enable end,
					order = 30,
				},
				buffcolor = {
					type = 'color',
					name = L['Buff Color'],
					desc = L['Set the color of the bars for buffs'],
					get = getcolor,
					set = setcolor,
					hasAlpha = true,
					passValue = {unit, 'buffcolor'},
					hidden = function() return not self.db.profile.Units[unit].enable end,
					order = 31,
				},
				Debuffs = {
					type = 'group',
					name = L['Debuff Colors'],
					desc = L['Set the color of the bars for debuffs'],
					hidden = function() return not self.db.profile.Units[unit].enable end,
					order = 32,
					args = {
						Normal = {
							type = 'color',
							name = L['Normal'],
							desc = L['Set color for normal'],
							get = getcolor,
							set = setcolor,
							order = 1,
							hasAlpha = true,
							passValue = {unit, 'debuffcolor'},
						},
						differentColors = {
							type = 'toggle',
							name = L['Different colors'],
							desc = L['Different colors for different debuffs types'],
							get = get,
							set = set,
							order = 2,
							passValue = {unit, 'differentColors'},
						},
						Curse = {
							type = 'color',
							name = L['Curse'],
							desc = L['Set color for curses'],
							get = getcolor,
							set = setcolor,
							order = 5,
							hasAlpha = true,
							passValue = {unit, 'Cursecolor'},
							hidden = function(unit) return not self.db.profile.Units[unit[1]].differentColors end,
						},
						Poison = {
							type = 'color',
							name = L['Poison'],
							desc = L['Set color for poisons'],
							get = getcolor,
							set = setcolor,
							order = 6,
							hasAlpha = true,
							passValue = {unit, 'Poisoncolor'},
							hidden = function(unit) return not self.db.profile.Units[unit[1]].differentColors end,
						},
						Magic = {
							type = 'color',
							name = L['Magic'],
							desc = L['Set color for magics'],
							get = getcolor,
							set = setcolor,
							order = 7,
							hasAlpha = true,
							passValue = {unit, 'Magiccolor'},
							hidden = function(unit) return not self.db.profile.Units[unit[1]].differentColors end,
						},
						Disease = {
							type = 'color',
							name = L['Disease'],
							desc = L['Set color for diseases'],
							get = getcolor,
							set = setcolor,
							order = 8,
							hasAlpha = true,
							passValue = {unit, 'Diseasecolor'},
							hidden = function(unit) return not self.db.profile.Units[unit[1]].differentColors end,
						},
					}
				},
				backgroundcolor = {
					type = 'color',
					name = L['Background Color'],
					desc = L['Set the color of the bars background'],
					get = getcolor,
					set = setcolor,
					hasAlpha = true,
					passValue = {unit, 'backgroundcolor'},
					hidden = function() return not self.db.profile.Units[unit].enable end,
					order = 32,
				},
				click = {
					type = 'toggle',
					name = L['Use Clicks'],
					desc = L['Print timeleft and move name on right click for the %s']:format(L[unit]),
					get = get,
					set = set,
					passValue = {unit, 'click'},
					hidden = function() return not self.db.profile.Units[unit].enable end,
					order = 41,
				},
				nametext = {
					type = 'toggle',
					name = L['Name Text'],
					desc = L['Display the names of buffs/debuffs on their bars'],
					get = get,
					set = set,
					passValue = {unit, 'nametext'},
					hidden = function() return not self.db.profile.Units[unit].enable end,
					order = 42,
				},
				showicons = {
					type = 'toggle',
					name = L['Show Icons'],
					desc = L['Show icons on buffs and debuffs for your %s']:format(L[unit]),
					get = get,
					set = set,
					passValue = {unit, 'icons'},
					order = 43,
					hidden = function() return not self.db.profile.Units[unit].enable end,
				},
				showiconsOnly = {
					type = 'toggle',
					name = L['Show Only Icons'],
					desc = L['Show only icons and timeleft for your %s']:format(L[unit]),
					get = get,
					set = set,
					passValue = {unit, 'showIcons'},
					order = 44,
					hidden = function() return not self.db.profile.Units[unit].enable end,
				},
				growUp = {
					type = 'toggle',
					name = L['Grow Up'],
					desc = L['Set %s bars to grow up']:format(L[unit]),
					get = get,
					set = set,
					order = 45,
					passValue = {unit, 'growup'},
					hidden = function() return not self.db.profile.Units[unit].enable end,
				},
				reversed = {
					type = 'toggle',
					name = L['Reversed'],
					desc = L['Reverse the bars for your %s']:format(L[unit]),
					get = get,
					set = set,
					order = 46,
					passValue = {unit, 'reversed'},
					hidden = function() return not self.db.profile.Units[unit].enable end,
				},
				timetext = {
					type = 'toggle',
					name = L['Time Text'],
					desc = L['Display the time remaining on buffs/debuffs on their bars'],
					get = get,
					hidden = function() return not self.db.profile.Units[unit].enable end,
					set = set,
					passValue = {unit, 'timetext'},
					order = 47,
				},
			}
		}
	end

	ClassTimer.Menu = { 
	    type ='group',
	    args = {
			spacer = {
				type = 'header',
				order = 3,
			},
			BarSettings = {
				type = 'group',
				name = L['Bar Settings'],
				desc = L['Bar Settings'],
				order = 3,
				disabled = '~IsActive',
				args = {
					focus = Unit('focus'),
					target = Unit('target'),
					player = Unit('player'),
					pet = hasPet and Unit('pet') or nil,
					sticky = Unit('sticky'),
					spacer1 = {
						type = 'header',
						order = 10,
					},
					General = Unit('General'),
					spacer2 = {
						type = 'header',
						order = 21,
					},
					AllInOne = {
						type = 'text',
						name = L['AllInOne'],
						desc = L['Display all the buffs and debuffs on the AllInOne owner bar'],
						multiToggle = true,
						get = function(key) return self.db.profile.Group[key] end,
						set = function(key, value) 
							self.db.profile.Group[key] = value
							if not self.db.profile.AllInOneOwner then
								self.db.profile.AllInOneOwner = key 
							elseif self.db.profile.AllInOneOwner ~= unit then
								self.Menu.args.BarSettings.args.sticky.args.lock.set({unit}, true)
							end end,
						validate = {player = L['player'], target = L['target'], focus = L['focus'], pet = L['pet']},
						order = 22,
					},
					AllInOneParent = {
						type = 'text',
						name = L['AllInOne Owner'],
						desc = L['Display the AllInOne Bars this bar'],
						get = function() return self.db.profile.AllInOneOwner end,
						set = function(value) self.db.profile.AllInOneOwner = value self.db.profile.Group[value] = true  end,
						validate = {player = L['player'], target = L['target'], focus = L['focus'], pet = L['pet']},
						order = 22,
					}
				}
			}
		}
	}
end

ClassTimer.hasIcon = "Interface\\Icons\\Spell_Shadow_UnstableAffliction_2"
ClassTimer.cannotDetachTooltip = true
ClassTimer.hideWithoutStandby = true 
ClassTimer.hasNoColor = true
ClassTimer.OnMenuRequest = self.Menu
ClassTimer.blizzardTooltip = true
ClassTimer.independentProfile = true

function ClassTimer:OnClick()
	self.Menu.args.BarSettings.args.sticky.args.lock.set({'General'}, unlocked['General']) 
end

function ClassTimer:OnTooltipUpdate()
	GameTooltip:AddLine('ClassTimer')
	GameTooltip:AddLine(' ')
	GameTooltip:AddLine(L['|cffffff00Left-Click|r to unlock all the bars'], 0.2, 1, 0.2)
	GameTooltip:AddLine(L['|cffffff00Right-Click|r to open configuration menu'], 0.2, 1, 0.2)
end 
